/**
 * Copyright (c) suzuki ryoutoku
 * See this code regarding the Apache License Version 2.0
 * @file Reader.cpp
 */
//=============================================================================
//	pre processor
//=============================================================================

#include "Reader.h"
#include "Graphics.h"
#include <sstream>
#include <iomanip>
#include <sys/types.h>
#include <sys/stat.h>
using namespace library::graphics;
using namespace library::log;
using namespace std;
using namespace reader::max;

//=============================================================================
//	define's local class
//=============================================================================
/**
 * @author suzuki ryoutoku
 * @date 2007-12-16
 * @version 1.0
 */
struct readTriangle
{
  int index[3];
  int m_group_index;
};

/**
 * @author suzuki ryoutoku
 * @date 2007-12-16
 * @version 1.0
 */
struct readSquare
{
  int index[4];
  int m_group_index;
};

/**
 * @author suzuki ryoutoku
 * @date 2007-12-16
 * @version 1.0
 */
struct ReadGroup
{
  int m_index;
  list<int> m_triangles;
  list<int> m_squares;
  ReadGroup(){
	m_index = 0;
  }
  ~ReadGroup(){
	m_triangles.clear();
	m_squares.clear();
  }
};


//=============================================================================
//	library::graphics::Reader's class member
//=============================================================================
/**
 * sum of character per one line
 * @author suzuki ryoutoku 
 */
const int library::graphics::Reader::NumberOfCharactersLine = 1024;

/**
 * This is comment symbol.
 * @author suzuki ryoutoku
 */
const char* library::graphics::Reader::Comment[] = {"#", "*"};

//=============================================================================
//	Reader's method
//=============================================================================
/**
 * @author suzuki ryoutoku 
 * @date 2007-10-14
 * @version 1.0
 */
library::graphics::Reader::Reader(library::log::LogManager* arg)
{
  this->_log_manager = arg;
}

/**
 * @author suzuki ryoutoku 
 * @date 2007-10-14
 * @version 1.0
 */
library::graphics::Reader::~Reader()
{
  _texfilename.clear();
}

/**
 * This method's work is to check file is existing.
 * @author r-suzuki
 * @date 2008-12-9
 * @version 1.0
 */
bool library::graphics::Reader::isExisting(const char* filename)
{
  struct stat  st;
  if( stat(filename, &st) != 0 ){
	_log_manager->print("Read file name = %s is not existing\n",
						filename);
	return false;
  }else{
	return true;
  }
}

//=============================================================================
//	Reader's class method
//=============================================================================
/**
 * The work of this method is to check line.
 * If necessary to remove comment, this method do it.
 * @return false invalid line
 * 
 * @param arg eval string
 *
 * @author suzuki ryoutoku
 * @version 1.0
 */
bool library::graphics::Reader::CheckLine(string* arg)
{
  // cutting comment
  for( int i = 0; i < sizeof(Comment)/sizeof(char*); i++ ){
	if( string::npos != arg->find(string(Comment[i])) ){
	  arg->erase( arg->find(string(Comment[i])) );
	}
  }
  
  if( !arg->size() ) return false;
  
  return true;
}

/**
 * To examin how many data partitioned by the delimiter there is.
 * @param arg 
 * @param specify " " in defalut
 * @return number of data + 1
 * @version 1.0
 * @date 2006-04-26
 */
int library::graphics::Reader::CountData(const string& arg, 
										 const string specify)
{
  size_t start_point = 0;
  int count = 0;
  size_t pre_point = -1;// When One digit, process can go well.
  while( string::npos != ( start_point = arg.find(specify, start_point) ) ){
	if( arg.find(specify, start_point) == (arg.size()-1) ){
	  break;
	}

	// If specified character is continuousness, no count.
	if( pre_point != start_point-1 ){
	  count++;
	}
	pre_point = start_point;
	start_point += 1;

  }
  return (count + 1);
}


/**
 * This method extract model name from file path involved directory.
 * @version 1.0
 * @date 2006-08-22
 */
void library::graphics::Reader::ExtractModelName(const string& arg, 
												 char* model)
{
  size_t end_pos = arg.rfind(string("."));
  size_t start_pos = 0;
  
  char* tmp = (char*)arg.c_str();
  
  
  while( NULL != (tmp = strstr(tmp, "\\") ) ){
	tmp += 1;
	start_pos = tmp - arg.c_str();
  }
  
  for( size_t i = start_pos; i < end_pos; i ++){
	model[i - start_pos] = arg.c_str()[i];
  }
  model[end_pos-start_pos] = '\0';
}

/**
 * This method is class method.
 * The work is to create sub class of Reader at filename.
 * @author r-suzuki
 * @version 1.0
 */
library::graphics::Reader* 
library::graphics::Reader::CreateReader(const string& filename,
										library::log::LogManager* arg)
{
  if( string::npos != filename.rfind(".3ds") ||
	  string::npos != filename.rfind(".3DS") ){
	return new Read3ds(arg);
  }else if( string::npos != filename.rfind(".vdf") ||
			string::npos != filename.rfind(".VDF") ){
	return new ReadVdf(arg);
  }else if( string::npos != filename.rfind(".pcm") ||
			string::npos != filename.rfind(".pcm") ){
	return new ReadPcm(arg);
  }else{
	arg->print("Error %s is unsupport file.",
			   filename.c_str());
	return NULL;
  }
}


//=============================================================================
//	library::graphics::Read3ds's method
//=============================================================================
/**
 * @author suzuki ryoutoku 
 * @date 2008-1-2
 * @version 1.0
 */
library::graphics::Read3ds::Read3ds(library::log::LogManager* arg)
  : library::graphics::Reader(arg)
{
}

/**
 * @author suzuki ryoutoku 
 * @date 2008-1-2
 * @version 1.0
 */
library::graphics::Read3ds::~Read3ds()
{
  vector<reader::max::Object*>::iterator ite = m_objects.begin();
  while( ite != m_objects.end() ){
	delete (*ite);
	ite++;
  }
  m_objects.clear();
  vector<reader::max::Material*>::iterator mite = _material.begin();
  while( mite != _material.end() ){
	delete (*mite);
	mite++;
  }
  _material.clear();
}

/**
 * This method is called outside.
 * \note
 * @param filename is 3ds file involved absolute path.
 * @return If value was NULL, failure occurs.
 *
 * @author suzuki ryoutoku 
 * @date 2008-1-2
 * @version 1.0
 */
library::graphics::Model* 
library::graphics::Read3ds::read(const string& filename)
{
  FILE* fp;
  char tmp[256];
  if( false == this->isExisting(filename.c_str()) ){
	return NULL;
  }
  _log_manager->print("Read file name = %s\nreading start time =%s\n",
							filename.c_str(),
							this->_log_manager->storeTime(tmp));
  
  fp = fopen(filename.c_str(),"rb");

  Chunk fileChunk;
  unsigned int current_reading_size = 0;

  // First, This is first chunk read,it's stored id 0x4d4d and total file size.
  current_reading_size += fileChunk.readFile(fp);
  fileChunk.display();

  while( current_reading_size < fileChunk.m_length ){
	Chunk chunk;
	current_reading_size += chunk.readFile(fp);
	switch( chunk.m_ID ){
	case EDIT3DS:
	  this->readEdit3ds(fp, &chunk);
	  current_reading_size += (chunk.m_length-Chunk::DATASIZE);
	  break;
	default:
	  current_reading_size += chunk.skipFile(fp);
	}
  }
  Model* model =  createModelData();
  
  
  fclose(fp);
  setTexfilename();

  this->Reader::_log_manager->print("reading end time =%s\n\n",
									 this->_log_manager->storeTime(tmp));
  return model;
}

/**
 * This method read a EDIT3DS chunk from 3ds file.
 *
 * @param fp must be 3ds file
 * @param head must be EDIT3DS's chunk header
 *
 * @author suzuki ryoutoku
 * @version 1.0
 * @date 2008-2-13
 */
void library::graphics::Read3ds::readEdit3ds(FILE* fp, 
											 reader::max::Chunk* head)
{
  unsigned int readsize = head->m_bytesread;
  while( readsize < head->m_length ){
	Chunk tmpChunk;
	readsize += tmpChunk.readFile(fp);
	switch( tmpChunk.m_ID ){
	case OBJECT:
	  readObject(fp, &tmpChunk);
	  break;
	case MATERIAL:
	  readMaterial(fp, &tmpChunk);
	  break;
	default:
	  tmpChunk.skipFile(fp);
	}
	readsize += tmpChunk.m_length;
  }
}

/**
 * This method reads object chunk in 3ds file.
 * @param fp must be 3ds file pointer
 * @param head must be object chunk's head information
 * @author suzuki ryoutoku
 * @version 1.0
 * @date 2008-2-14
 */
void library::graphics::Read3ds::readObject(FILE* fp, 
											reader::max::Chunk* head)
{
  char buffer[256];
  reader::max::Object* maxobj = new reader::max::Object;// create max::Object instance

  this->m_cobject.push(maxobj);
  // object must have name
  head->m_bytesread += getName(fp, buffer);
  cout << "   name=[" << buffer << "]" << endl;
  this->m_cobject.top()->setM_name(buffer);
  while( head->m_bytesread < head->m_length ){
	Chunk tmpChunk;
	tmpChunk.readFile(fp);
	switch( tmpChunk.m_ID ){
	case OBJECT_MESH:
	  readMesh(fp, &tmpChunk);
	  break;
	default:
	  tmpChunk.skipFile(fp);
	}
	head->m_bytesread += tmpChunk.m_length;
  }
  this->m_cobject.pop();

  if( maxobj->isModelData() ){
	this->m_objects.push_back(maxobj);
  }else{
	delete maxobj;
  }

}

/**
 * This method reads mesh chunk in 3ds file.
 * @param fp 3ds file pointer
 * @param head mesh chunk's head information
 * @author suzuki ryoutoku
 * @version 1.0
 * @date 2008-2-14
 */
void library::graphics::Read3ds::readMesh(FILE* fp, reader::max::Chunk* head)
{
  while( head->m_bytesread < head->m_length ){
	Chunk tmpChunk;
	tmpChunk.readFile(fp);
	switch( tmpChunk.m_ID ){
	case MESH_VERTICES:
	  readMeshVertices(fp, &tmpChunk);
	  break;
	case MESH_FACES:
	  readMeshFaces(fp, &tmpChunk);
	  break;
	case MESH_MATERIAL:
	  readMeshMaterial(fp, &tmpChunk);
	  break;
	case MESH_TEXTURE_COORD:
	  readMeshTextureCoord(fp, &tmpChunk);
	  break;
	default:
	  tmpChunk.skipFile(fp);
	}
	head->m_bytesread += tmpChunk.m_length;
  }
}

/**
 * This method read MATERIAL chunk.
 * @author suzuki ryoutoku
 * @version 1.0
 * @date 2008-2-14
 */
void library::graphics::Read3ds::readMaterial(FILE* fp, 
											  reader::max::Chunk* head)
{
  char buffer[256];
  bool flag = false;
  memset(buffer,0,256);
  if( this->m_cmaterial.empty() ){
	reader::max::Material* mat = new reader::max::Material;  // create max::Material instance
	this->_material.push_back(mat);
	this->m_cmaterial.push(mat);
	flag = true;
  }


  while( head->m_bytesread < head->m_length ){
	Chunk tmpChunk;
	tmpChunk.readFile(fp);
	switch( tmpChunk.m_ID ){
	case MATERIAL_NAME:
	  if( flag == false ){
		reader::max::Material* mat = new reader::max::Material;// create max::Material instance
		this->_material.push_back(mat);
		this->m_cmaterial.push(mat);
		flag = true;
	  }
	  tmpChunk.m_bytesread += getName(fp,buffer);
	  cout << "   name=[" << buffer << "]" << endl;
	  this->m_cmaterial.top()->setM_name(buffer);
	  break;
	case MATERIAL_DIFFUSE:
	  readDiffuse(fp, &tmpChunk);
	  break;
	case MATERIAL_TEXMAP:
	  // MATERIAL can calls itself recursivily.
	  readMaterial(fp, &tmpChunk);
	  break;
	case MATERIAL_TEXFILE:
	  tmpChunk.m_bytesread += getName(fp,buffer);
	  cout << "   texfile=[" << buffer << "]" << endl;
	  this->m_cmaterial.top()->setM_texture_filename(buffer);
	  break;
	default:
	  tmpChunk.skipFile(fp);
	}
	head->m_bytesread += tmpChunk.m_length;
  }

  if( flag == false ){
	this->m_cmaterial.pop();
  }
}


/**
 * This method read MATERIAL_DIFFUSE chunk.
 * @author suzuki ryoutoku
 * @version 1.0
 * @date 2008-2-14
 */
void library::graphics::Read3ds::readDiffuse(FILE* fp, 
											 reader::max::Chunk* head)
{
  Chunk tmpChunk;
  unsigned char r,g,b;
  tmpChunk.readFile(fp);
  tmpChunk.m_bytesread += fread(&r,1,sizeof(unsigned char),fp);
  tmpChunk.m_bytesread += fread(&g,1,sizeof(unsigned char),fp);
  tmpChunk.m_bytesread += fread(&b,1,sizeof(unsigned char),fp);
  cout << "   [rgb]";
  cout << setw(2) << setbase(16) 
	   << (unsigned int)r << ":" 
	   << setw(2) << setbase(16) 
	   << (unsigned int)g << ":" 
	   << setw(2) << setbase(16) 
	   << (unsigned int)b << endl;
  cout << setbase(10);
  this->m_cmaterial.top()->m_diffuse[0]=r;
  this->m_cmaterial.top()->m_diffuse[1]=g;
  this->m_cmaterial.top()->m_diffuse[2]=b;

  tmpChunk.skipFile(fp);
  
  head->m_bytesread += tmpChunk.m_length;
}

/**
 * This method reads vertex of mesh chunk in 3ds file.
 * @param fp 3ds file pointer
 * @param head vertex of mesh chunk's head information
 * @author suzuki ryoutoku
 * @version 1.0
 * @date 2008-2-14
 */
void library::graphics::Read3ds::readMeshVertices(FILE* fp, 
												  reader::max::Chunk* head)
{
  unsigned short number_vertices = 0;
  head->m_bytesread += fread(&number_vertices,
							 1,
							 sizeof(unsigned short),
							 fp);

  cout << "   number of vertex = " << number_vertices << endl;

  if( 0 == number_vertices ) return;

  for(int i=0; i < number_vertices; i++){
	float coord[3];
	head->m_bytesread += fread(&(coord[0]), sizeof(float), 1, fp);
	head->m_bytesread += fread(&(coord[1]), sizeof(float), 1, fp);
	head->m_bytesread += fread(&(coord[2]), sizeof(float), 1, fp);
	this->m_cobject.top()->m_coord.push_back(coord[0]);
	this->m_cobject.top()->m_coord.push_back(coord[1]);
	this->m_cobject.top()->m_coord.push_back(coord[2]);
  }

  this->m_cobject.top()->m_vertexsum+=number_vertices;
}

/**
 * This method reads face of mesh chunk in 3ds file.
 * @param fp 3ds file pointer
 * @param head face of mesh chunk's head information
 * @author suzuki ryoutoku
 * @version 1.0
 * @date 2008-2-14
 */
void library::graphics::Read3ds::readMeshFaces(FILE* fp, 
											   reader::max::Chunk* head)
{
  unsigned short number_faces = 0;
  head->m_bytesread += fread(&number_faces,
							 1,
							 sizeof(unsigned short),
							 fp);
  cout << "   number of faces = " << number_faces << endl;
  
  //  head->skipFile(fp);
  for(int i=0; i <  number_faces; i++){
	unsigned short index[3];
	unsigned short poly_flag;
	fread(&(index[0]), sizeof(unsigned short), 1, fp);
	fread(&(index[1]), sizeof(unsigned short), 1, fp);
	fread(&(index[2]), sizeof(unsigned short), 1, fp);
	fread(&poly_flag, sizeof (unsigned short), 1, fp);
	this->m_cobject.top()->m_index.push_back(index[0]);
	this->m_cobject.top()->m_index.push_back(index[1]);
	this->m_cobject.top()->m_index.push_back(index[2]);
  }
  this->m_cobject.top()->m_trianglesum=number_faces;
  // Face chunk have child chunk.
  // I recursively call readMesh();
  head->m_bytesread += number_faces*8;
  readMesh(fp, head);
}

/**
 * This method reads face of mesh chunk in 3ds file.
 * @param fp 3ds file pointer
 * @param head material of face chunk's head information
 * @author suzuki ryoutoku
 * @version 1.0
 * @date 2008-2-14
 */
void library::graphics::Read3ds::readMeshMaterial(FILE* fp, 
												  reader::max::Chunk* head)
{
  char buffer[256];
  head->m_bytesread += getName(fp, buffer);
  unsigned short number_face;

  head->m_bytesread += fread(&number_face, 1, sizeof(unsigned short), fp);
  cout << "   number of faces in [" 
	   << buffer 
	   <<"]= " 
	   << number_face << endl;
  if( number_face == 0 ){
	head->skipFile(fp);
	return;
  }

  reader::max::FaceGroup* fg = new FaceGroup();
  fg->setM_materialname(buffer);
  

  for( int i = 0; i < number_face; i++ ){
	unsigned short tmp;
	fread(&tmp, 1, sizeof(unsigned short), fp);
	fg->m_faces.push_back(tmp);
  }
  if( 0 != fg->m_faces.size() ){
	this->m_cobject.top()->m_group.push_back(fg);
  }else{
	delete fg;
  }
}

/**
 * This method reads texture coords of mesh chunk in 3ds file.
 * @param fp 3ds file pointer
 * @param head  texture coords of mesh chunk's head information
 * @author suzuki ryoutoku
 * @version 1.0
 * @date 2008-2-14
 */
void library::graphics::Read3ds::readMeshTextureCoord(FILE* fp, 
													  reader::max::Chunk* head)
{
  unsigned short number_texcoord = 0;
  head->m_bytesread += fread(&number_texcoord,
							 1,
							 sizeof(unsigned short),
							 fp);
  cout << "   number of texcoord = " << number_texcoord << endl;
  for(int i=0; i < number_texcoord; i++){
	float texcoord[2];
	head->m_bytesread += fread(texcoord, sizeof(float), 2, fp);
	this->m_cobject.top()->m_uv.push_back(texcoord[0]);
	this->m_cobject.top()->m_uv.push_back(texcoord[1]);
	//cout << "    " << texcoord[0] << "," << texcoord[1] << endl;
  }
  this->m_cobject.top()->m_uvsum = number_texcoord;
}

/**
 * This method build instance of class Model.
 * 
 * @return If value was NULL, failure occurs.
 *
 * @author suzuki ryoutoku
 * @version 1.0
 * @date 2008-2-22
 */
library::graphics::Model* library::graphics::Read3ds::createModelData(void)
{
  Model* model = new Model;

  for( int i = 0; i < this->m_objects.size(); i++ ){
	reader::max::Object* obj = this->m_objects[i];
	// creating body
	library::graphics::PolygonBody* body 
	  = new library::graphics::PolygonBody(m_objects[i]->m_vertexsum);
	if( obj->m_uvsum != 0 ){
	  body->allocateUV();
	}

	// creating vertex and uv value
	for( int j = 0; j < (int)(obj->m_vertexsum); j++ ){
	  Vector<double> vertex((double)(obj->m_coord[j*3+0]),
							(double)(obj->m_coord[j*3+2]),
							(double)(-1.0*obj->m_coord[j*3+1]),
							1.0);
	  body->set_vertex(j,vertex);
	  Vector2D<float> uv;
	  if( obj->m_uvsum == 0 ) continue;
	  if( obj->m_uv[2*j+0] <= 1.0 ){
		uv.u = (obj->m_uv[2*j+0]);
	  }else{
		// it's repeat
		uv.u = (obj->m_uv[2*j+0] - 1.0f);
	  }
	  if( obj->m_uv[2*j+1] <= 1.0 ){
		uv.v = (1.0 - obj->m_uv[2*j+1]);
	  }else{
		uv.v = (obj->m_uv[2*j+1] - 1.0f);
	  }
	  body->set_uv(j,uv);
	}
	if( strlen(obj->m_name) != 0 ){
	  body->set_name(obj->m_name);
	}else{
	  char tmp[20];
	  sprintf(tmp,"v_%d", i);
	  body->set_name(tmp);
	}
	vector<char> belong(obj->m_trianglesum);
	unsigned short count = 0;
	int cluster_index = 0;
	  
	// creating group and cluster
	for( size_t j = 0; j < obj->m_group.size(); j++ ){
	  reader::max::FaceGroup* fg = obj->m_group[j];
	  library::graphics::Group* group = new Group(Group::TEXTURE,
												  Group::CLUSTER);
	  unsigned int matindex = this->getMaterialIndex(fg->m_materialname);
	  Color<float> color(this->_material[matindex]->m_diffuse[0],
						 this->_material[matindex]->m_diffuse[1],
						 this->_material[matindex]->m_diffuse[2]);

	  // Created normal group (belong to material)
	  memset(&(belong[0]),0,obj->m_trianglesum);
	  group->set_color(color);
	  if( this->_material[matindex]->m_texture_filename != '\0' ){
		group->set_texname(_material[matindex]->m_texture_filename);
		group->set_name(fg->m_materialname);
	  }

	  library::graphics::Cluster* cluster 
		= new TriangleCluster(fg->m_faces.size());
	  for( unsigned int k = 0; k < fg->m_faces.size(); k ++ ){
		unsigned short index = fg->m_faces[k];
		int order[3];
		order[0] = obj->m_index[index*3+0];
		order[1] = obj->m_index[index*3+1];
		order[2] = obj->m_index[index*3+2];
		belong[index]=1;
		cluster->setPolygon(body, k, static_cast<const int>(count), order);
		count++;
	  }
	  body->appendCluster(cluster);
	  group->addTarget(cluster_index++);
	  body->appendGroup(group);
	}
	  
	// creating unnormal group (no belong to material)
	// There are faces to no belong group.
	if( count < obj->m_trianglesum ){
	  int tmp_face_sum=obj->m_trianglesum - count;
#ifdef DEBUG
	  cout << "["<<obj->m_name<<"]"<<endl;
	  cout << "There are faces to no belong group. A number of faces is "
		   << tmp_face_sum
		   <<endl;
#endif
	  Group* group = new Group(Group::TEXTURE, Group::CLUSTER);
	  Cluster* cluster = new TriangleCluster(tmp_face_sum);
	  int group_poly_counter = 0;
	  for(unsigned int j = 0; j < belong.size(); j ++ ){
		if( belong[j] == 1 ) continue;
		int order[3];
		order[0] = obj->m_index[j*3+0];
		order[1] = obj->m_index[j*3+1];
		order[2] = obj->m_index[j*3+2];
		cluster->setPolygon(body, group_poly_counter++,
							static_cast<const int>(count), order);
		count++;
	  }
	  body->appendCluster(cluster);
	  group->addTarget(cluster_index++);
	  body->appendGroup(group);
	}
	body->appendGroup(new Group(Group::SELECTION, 
								Group::POLYGON));
	body->appendGroup(new Group(Group::SELECTION, 
								Group::VERTEX));
	model->appendPolygonBody(body);
	_log_manager->print(" Body[%d]name=%s\n",
						i,
						body->get_name());
	_log_manager->print("  polygon sum =%d cluster sum = %d vertex sum =%d\n",
						body->getFaceSum(),
						body->getClusterSum(),
						body->get_vertex_sum());
  }
  model->createCenter();
  return model;
}

/**
 * @author suzuki ryoutoku
 * @version 1.0
 * @date 2008-2-23
 */
unsigned int library::graphics::Read3ds::getMaterialIndex(const char* name)
  throw (char*)
{
  for( unsigned int i = 0 ; i < this->_material.size(); i ++ ){
	if( 0 == strcmp(name, this->_material[i]->m_name) ){
	  return i;
	}
  }
  throw "Read3ds::getMaterialIndex can not find material\n";
  return 0;
}

/**
 * @author r-suzuki
 * @date 2008-12-8
 * @version 1.0
 */
void library::graphics::Read3ds::setTexfilename(void)
{
  if( _material.size() == 0 ) return;
  vector<reader::max::Material*>::iterator ite = _material.begin();
  while( ite != _material.end() ){
	if( (*ite)->getM_texture_filename() != NULL &&
		(*ite)->getM_texture_filename()[0] != '\0'
		){
	  _texfilename.push_back(string((*ite)->getM_texture_filename()));
	}
	ite++;
  }
}

//=============================================================================
//	reader::max::Chunk's method
//=============================================================================
/**
 * @author suzuki ryoutoku
 * @version 1.0
 * @date 2008-2-5
 */
Chunk::Chunk()
{
  memset(this,0,sizeof(Chunk));
}

/**
 * @author suzuki ryoutoku
 * @version 1.0
 * @date 2008-2-5
 */
void Chunk::display()
{
  cout << "Chunk ID: 0x" << setw(4) << setfill('0') 
	   << setbase(16) << this->m_ID << " ";
  cout << setbase(10) << "length: "<< this->m_length << endl;
}

/**
 * This method reads id and length of latter this chunk from 3ds file.
 *
 * @param fp this must be 3ds file.
 *
 * @return reading a number of byte.
 *
 * @author suzuki ryoutoku
 * @version 1.0
 * @date 2008-2-5
 */
unsigned int Chunk::readFile(FILE* fp)
{
  this->m_bytesread = 0;
  this->m_bytesread += fread(&(this->m_ID), 1, sizeof(unsigned short), fp);
  this->m_bytesread += fread(&(this->m_length), 1, sizeof(unsigned int), fp);
  
  return (this->m_bytesread);
}

/**
 * This method skips byte data in 3ds file. 
 * @param fp this must be 3ds file.
 *
 *
 * @author suzuki ryoutoku
 * @version 1.0
 * @date 2008-2-6
 */
unsigned int Chunk::skipFile(FILE* fp)
{
  if( this->m_length > this->m_bytesread ){
	fseek(fp,this->m_length-this->m_bytesread,SEEK_CUR);
  }
  return this->m_length-Chunk::DATASIZE;
}

/**
 * This method extracts a name data from 3ds file. 
 *
 * @author suzuki ryoutoku
 * @version 1.0
 * @date 2008-2-6
 */
unsigned int reader::max::getName(FILE* fp, char* name)
{
  unsigned int index = 0;
  fread(&(name[index]), 1, 1, fp);
  while( name[index++] != 0 ){
	fread(&(name[index]), 1, 1, fp);
  }

  return index;
}


//=============================================================================
//	reader::max::Chunk's static member
//=============================================================================
/**
 * This static member is a size of only chunk.
 * @author suzuki ryoutoku
 * @version 1.0
 * @date 2008-2-5
 */
unsigned int reader::max::Chunk::DATASIZE = 6;

//=============================================================================
//	reader::max::Object's method
//=============================================================================
/**
 * @author suzuki ryoutoku 
 * @date 2008-1-2
 * @version 1.0
 */

reader::max::Object::Object()
{
  memset(this->m_name, 0, 20);
  this->m_coord.clear();
  this->m_index.clear();
  this->m_last_total_vertexsum = 0;
  this->m_vertexsum=0;
  this->m_trianglesum=0;
  this->m_uvsum = 0;
  this->m_uv.clear();
  this->m_group.clear();
}

/**
 * @author suzuki ryoutoku 
 * @date 2008-1-2
 * @version 1.0
 */
reader::max::Object::~Object()
{
  this->m_coord.clear();
  this->m_index.clear();
  this->m_uv.clear();
  vector<reader::max::FaceGroup*>::iterator ite = this->m_group.begin();
  while( ite != this->m_group.end() ){
	 delete (*ite);
	 ite++;
  }
}

/**
 * @author suzuki ryoutoku
 * @version 1.0
 * @date 2008-2-22
 */
bool reader::max::Object::isModelData(void)
{
  bool retval = true;
  if( m_coord.size() == 0 ){
	retval = false;
  }
  if( m_index.size() == 0 ){
	retval = false;
  }
#ifdef DEBUG
  if( retval == false ){
	cout << "    " << this->m_name << " is not 3d object" << endl;
  }
#endif
  return retval;
}

/**
 * @author suzuki ryoutoku
 * @version 1.0
 * @date 2008-2-24
 */
unsigned int Object::queryGroupSum(void)
{
  unsigned int tmpsum=0;
  for( unsigned int i =0; i < this->m_group.size(); i ++ ){
	tmpsum+=this->m_group[i]->m_faces.size();
  }
  if( this->m_trianglesum != tmpsum ){
	return (this->m_group.size()+1);
  }
  return this->m_group.size();
}

//=============================================================================
//	reader::max::FaceGroup's method
//=============================================================================
/**
 * @author suzuki ryoutoku
 * @version 1.0
 * @date 2008-2-15
 */
FaceGroup::FaceGroup()
{
  memset(this->m_materialname,0, 20);
  this->m_faces.clear();
}

/**
 * @author suzuki ryoutoku
 * @version 1.0
 * @date 2008-2-15
 */
FaceGroup::~FaceGroup()
{
  this->m_faces.clear();
}

//=============================================================================
//	reader::max::Material's method
//=============================================================================
/**
 * @author suzuki ryoutoku
 * @version 1.0
 * @date 2008-2-20
 */
reader::max::Material::Material()
{
  memset(this,0,sizeof(Material));
}

/**
 * @author suzuki ryoutoku
 * @version 1.0
 * @date 2008-2-20
 */
reader::max::Material::~Material()
{
}


//=============================================================================
//	ReadVdf's method
//=============================================================================
library::graphics::ReadVdf::ReadVdf(library::log::LogManager* arg)
  : library::graphics::Reader(arg)
{
}

library::graphics::ReadVdf::~ReadVdf()
{
}

/**
 * This method reads vdf file, and creates Model data.
 * @author r-suzuki
 * @version 1.0
 */
Model* library::graphics::ReadVdf::read(const string& filename)
{
  if( false == this->isExisting(filename.c_str()) ){
	return NULL;
  }

  ifstream fin(filename.c_str());
  char buffer[Reader::NumberOfCharactersLine];

  if( !fin ) return NULL;
  _log_manager->print("Read file name = %s\nstart time =%s\n",
					  filename.c_str(),
					  this->_log_manager->storeTime(buffer));

  // Until file end, reading each lines.
  while( fin.getline( buffer, NumberOfCharactersLine ) ){
	string line(buffer);

	if( string::npos != line.rfind(string("\r")) ){
	  line.erase( line.rfind(string("\r")) );
	}
	
	if( !Reader::CheckLine(&line) ) continue;
	
	// Reading label
	switch( readLabel(line) ){
	case ReadVdf::BODY:
	  readPolygonBody(fin);
	  break;
	case ReadVdf::NODAL_COORDNAITE:
	  readNodalCoordinate(fin);
	  break;
	case ReadVdf::UV:
	  readUV(fin);
	  break;
	case ReadVdf::RECTANGLE_CLUSTER:
	  readRectangleCluster(fin);
	  break;
	case ReadVdf::TRIANGLE_CLUSTER:
	  readTriangleCluster(fin);
	  break;
	case ReadVdf::GROUP:
	  readGroup(fin);
	  break;
	default:
	  cout << "Unkown label = " << line.c_str() << endl;
	}
  }

  library::graphics::Model* model = new library::graphics::Model;
  for( size_t i = 0; i < _bodies.size(); i++ ){
	if( 0== _bodies[i]->querySpecificGroupSum(Group::SELECTION, 
											  Group::VERTEX) ){
	  _bodies[i]->appendGroup(new Group(Group::SELECTION, 
								  Group::VERTEX));
	}
	if( 0== _bodies[i]->querySpecificGroupSum(Group::SELECTION, 
											  Group::POLYGON) ){
	  _bodies[i]->appendGroup(new Group(Group::SELECTION, 
								  Group::POLYGON));
	}
	model->appendPolygonBody(_bodies[i]);
  }
  model->createCenter();
  return model;
}


/**
 *
 * @author r-suzuki
 * @version 1.0
 */
unsigned int library::graphics::ReadVdf::readLabel(const string& label)
{
  unsigned int retval[] 
	= {ReadVdf::BODY,
	   ReadVdf::NODAL_COORDNAITE,
	   ReadVdf::UV,
	   ReadVdf::RECTANGLE_CLUSTER,
	   ReadVdf::TRIANGLE_CLUSTER,
	   ReadVdf::GROUP,
  };
  const char* labels[]
	= {"$PolygonBody",
	   "$NodalCoordinate",
	   "$UV",
	   "$RectangleCluster",
	   "$TriangleCluster",
	   "$Group",
  };
  
  for( int i = 0; i < 6; i++ ){
	if( 0 == strcmp(label.c_str(), labels[i]) ){
		return retval[i];
	}
  }
  return ReadVdf::NONE;
}

/**
 * @author r-suzuki
 * @date 2008-12-8
 * @version 1.0
 */
bool library::graphics::ReadVdf::readPolygonBody(ifstream& fin)
{
  char buffer[Reader::NumberOfCharactersLine];
  reader::vdf::Attribute attr;

  // Reading attribute
  this->readAttribute(fin, &attr);
  
  library::graphics::PolygonBody* body = new library::graphics::PolygonBody();
  body->set_name(attr._name);

  if( attr._sum == 0 ){
	_bodies.push_back(body);
	_current_body = body;
	return true;
  }

  
  // Reading Polygon
  // Now, Don not get a line, skipping polygon line.
  int counter = 0;
  while( fin.getline( buffer, NumberOfCharactersLine ) ){
	char* p = buffer;
	while( *p == '\t' || *p == ' ' ){
	  p++;
	}
	string line(p);

	if( string::npos != line.rfind(string("\r")) ){
	  line.erase( line.rfind(string("\r")) );
	}
	
	if( !Reader::CheckLine(&line) ) continue;
	counter++;
	if( counter >= attr._sum ) break;
  }
  _bodies.push_back(body);
  _current_body = body;
  return true;
}

/**
 * @author r-suzuki
 * @date 2008-12-8
 * @version 1.0
 */
bool library::graphics::ReadVdf::readNodalCoordinate(ifstream& fin)
{
  char buffer[Reader::NumberOfCharactersLine];
  reader::vdf::Attribute attr;
  
  // Reading attribute
  this->readAttribute(fin, &attr);  

  _current_body->allocateVertex(attr._sum);
  
  // Reading vertex's coordinate
  int counter = 0;
  while( fin.getline( buffer, NumberOfCharactersLine ) ){
	char* p = buffer;
	
	while( *p == '\t' || *p == ' ' ){
	  p++;
	}
	string line(p);

	if( string::npos != line.rfind(string("\r")) ){
	  line.erase( line.rfind(string("\r")) );
	}
	
	if( !Reader::CheckLine(&line) ) continue;
	
	int id;
	double x,y,z;
	sscanf(line.c_str(), 
		   "%d %lf %lf %lf",
		   &id,
		   &x,
		   &y,
		   &z);
	_current_body->set_vertex(counter, Vector<double>(x,y,z,1.0));
	_current_body->set_vertex_id(counter, id);
	counter++;
	if( counter >= attr._sum ) break;
  }
  return true;
}

bool library::graphics::ReadVdf::readUV(ifstream& fin)
{
  char buffer[Reader::NumberOfCharactersLine];
  reader::vdf::Attribute attr;

  // Reading attribute
  this->readAttribute(fin, &attr);

  _current_body->allocateUV();
  
  int counter = 0;
  while( fin.getline( buffer, NumberOfCharactersLine ) ){
	char* p = buffer;
	
	while( *p == '\t' || *p == ' ' ){
	  p++;
	}
	string line(p);

	if( string::npos != line.rfind(string("\r")) ){
	  line.erase( line.rfind(string("\r")) );
	}
	
	if( !Reader::CheckLine(&line) ) continue;
	
	int id;
	double u,v;
	sscanf(line.c_str(), 
		   "%d %lf %lf",
		   &id,
		   &u,
		   &v);
	_current_body->set_uv(id, Vector2D<float>(u,v));
	counter++;
	if( counter >= attr._sum ) break;
  }
  return true;
}


bool library::graphics::ReadVdf::readRectangleCluster(ifstream& fin)
{
  char buffer[Reader::NumberOfCharactersLine];
  reader::vdf::Attribute attr;
  // Reading attribute
  this->readAttribute(fin, &attr);
  library::graphics::Cluster* cluster = new RectangleCluster(attr._sum);

  int counter = 0;
  while( fin.getline( buffer, NumberOfCharactersLine ) ){
	char* p = buffer;

	while( *p == '\t' || *p == ' ' ){
	  p++;
	}
	string line(p);
	if( string::npos != line.rfind(string("\r")) ){
	  line.erase( line.rfind(string("\r")) );
	}
	if( !Reader::CheckLine(&line) ) continue;
	int id;
	int conne[4];
	sscanf(line.c_str(), 
		   "%d %d %d %d %d",
		   &id,
		   &(conne[0]),
		   &(conne[1]),
		   &(conne[2]),
		   &(conne[3]));
	cluster->setPolygon(_current_body, counter, id, conne);
	counter++;
	if( counter >= attr._sum ) break;
  }

  _current_body->appendCluster(cluster);
  
  return true;
}

bool library::graphics::ReadVdf::readTriangleCluster(ifstream& fin)
{
  char buffer[Reader::NumberOfCharactersLine];
  reader::vdf::Attribute attr;
  // Reading attribute
  this->readAttribute(fin, &attr);
  library::graphics::Cluster* cluster = new TriangleCluster(attr._sum);

  int counter = 0;
  while( fin.getline( buffer, NumberOfCharactersLine ) ){
	char* p = buffer;

	while( *p == '\t' || *p == ' ' ){
	  p++;
	}
	string line(p);
	if( string::npos != line.rfind(string("\r")) ){
	  line.erase( line.rfind(string("\r")) );
	}
	if( !Reader::CheckLine(&line) ) continue;
	int id;
	int conne[3];
	sscanf(line.c_str(), 
		   "%d %d %d %d",
		   &id,
		   &(conne[0]),
		   &(conne[1]),
		   &(conne[2]));
	cluster->setPolygon(_current_body, counter, id, conne);
	counter++;
	if( counter >= attr._sum ) break;
  }

  _current_body->appendCluster(cluster);
  
  return true;
}

bool library::graphics::ReadVdf::readGroup(ifstream& fin)
{
  char buffer[Reader::NumberOfCharactersLine];
  reader::vdf::Attribute attr;
  // Reading attribute
  this->readAttribute(fin, &attr);

  library::graphics::Group* group = new Group( attr._type, attr._target_type);
  group->set_name(attr._name);
  if( attr._data_name[0] != 0 ){
	group->set_texname(attr._data_name);
	_texfilename.push_back(string(attr._data_name));
  }

  int counter = 0;
  while( fin.getline( buffer, NumberOfCharactersLine ) ){
	char* p = buffer;
	while( *p == '\t' || *p == ' ' ){
	  p++;
	}
	string line(p);
	if( string::npos != line.rfind(string("\r")) ){
	  line.erase( line.rfind(string("\r")) );
	}
	if( !Reader::CheckLine(&line) ) continue;
	int id;
	sscanf(line.c_str(), 
		   "%d",
		   &id);
	group->addTarget(id);
	counter++;
	if( counter >= attr._sum ) break;
  }
  _current_body->appendGroup(group);
  return true;
}

bool library::graphics::ReadVdf::readAttribute(ifstream& fin, 
											   reader::vdf::Attribute* attr)
{
  char buffer[Reader::NumberOfCharactersLine];
  while( fin.getline( buffer, NumberOfCharactersLine ) ){
	string line(buffer);
	if( string::npos != line.rfind(string("\r")) ){
	  line.erase( line.rfind(string("\r")) );
	}
	if( !Reader::CheckLine(&line) ) continue;
	if( string::npos != line.find(string("target_id")) ){
	  sscanf( line.c_str(), "target_id=%d", &(attr->_target_id));
	}else if( string::npos != line.find(string("target_type")) ){
	  sscanf( line.c_str(), "target_type=%d", &(attr->_target_type));
	}else if( string::npos != line.find(string("id")) ){
	  sscanf( line.c_str(), "id=%d", &(attr->_id));
	}else if( string::npos != line.find(string("type")) ){
	  sscanf( line.c_str(), "type=%d", &(attr->_type));
	}else if( string::npos != line.find(string("dataname")) ){
	  sscanf( line.c_str(), "dataname=%s", attr->_data_name);
	}else if( string::npos != line.find(string("name")) ){
	  sscanf( line.c_str(), "name=%s", attr->_name);
	}else if( string::npos != line.find(string("sum")) ){
	  sscanf( line.c_str(), "sum=%d", &(attr->_sum));
	  // Temporary rule, sum attribute is end sign.
	  break;
	}
  }
  return true;
}

//=============================================================================
//	reader::vdf::Attribute's method
//=============================================================================
reader::vdf::Attribute::Attribute()
{
  memset(this, 0, sizeof(reader::vdf::Attribute));
}

//=============================================================================
//	ReadVdf's method
//=============================================================================
library::graphics::ReadPcm::ReadPcm(library::log::LogManager* arg)
  : Reader(arg)
{
}

library::graphics::ReadPcm::~ReadPcm()
{
  _coord.clear();
  vector<reader::pcm::Volume*>::iterator ite = _volumes.begin();
  while(ite != _volumes.end() ){
	delete *ite;
	ite++;
  }
  _volumes.clear();
}

library::graphics::Model* 
library::graphics::ReadPcm::read(const string& filename)
{
  char buffer[256];
  if( false == this->isExisting(filename.c_str()) ){
	return NULL;
  }

  ifstream fin(filename.c_str());

  if( !fin ) return NULL;
  _log_manager->print("Read file name = %s\nstart time =%s\n",
					  filename.c_str(),
					  this->_log_manager->storeTime(buffer));

  // read volume sum and vertex sum
  readHeader(fin);

  // read vertex term
  readVertexTerm(fin);
  
  // read volume term
  for( size_t i = 0; i < _volumes.size(); i++ ){
	readVolumeTerm(fin, i);
  }

  return createModel();
}

/**
 * This method is private.
 * The work is read header in pcm file.
 * @author r-suzuki
 * @date 2009-1-19
 * @version 1.0
 */
int library::graphics::ReadPcm::readHeader(ifstream& fin)
{
  char buffer[Reader::NumberOfCharactersLine];
  while( fin.getline( buffer, NumberOfCharactersLine ) ){
	string line(buffer);

	if( string::npos != line.rfind(string("\r")) ){
	  line.erase( line.rfind(string("\r")) );
	}

	if( !Reader::CheckLine(&line) ) continue;

	int versum, volumesum, tmp;
	sscanf(line.c_str(),
		   "%d %d %d",
		   &versum,
		   &tmp,
		   &volumesum);

	_coord.resize(versum);
	_volumes.resize(volumesum);
	break;
  }
  for( int i = 0; i < _volumes.size(); i++ ){
	_volumes[i] = new reader::pcm::Volume;
  }
  return 0;
}

int library::graphics::ReadPcm::readVertexTerm(ifstream& fin)
{
  char buffer[Reader::NumberOfCharactersLine];
  int counter = 0;

  while( counter < _coord.size() &&
		 fin.getline( buffer, NumberOfCharactersLine ) ){
	string line(buffer);

	if( string::npos != line.rfind(string("\r")) ){
	  line.erase( line.rfind(string("\r")) );
	}

	if( !Reader::CheckLine(&line) ) continue;

	double x,y,z;
	sscanf(line.c_str(),
		   "%lf %lf %lf",
		   &x,
		   &y,
		   &z);
	_coord[counter]._global_id = counter;
	_coord[counter]._coord = library::mathematics::Vector<double>(x,y,z,1.0);
	counter++;
  }
  return 0;
}

int library::graphics::ReadPcm::readVolumeTerm(ifstream& fin, size_t index)
{
  char buffer[Reader::NumberOfCharactersLine];
  
  // read face sum
  while( fin.getline( buffer, NumberOfCharactersLine ) ){
	string line(buffer);

	if( string::npos != line.rfind(string("\r")) ){
	  line.erase( line.rfind(string("\r")) );
	}

	if( !Reader::CheckLine(&line) ) continue;

	int facesum, innerfacesum, inneredgesum;
	sscanf(line.c_str(),
		   "%d %d %d",
		   &facesum,
		   &innerfacesum,
		   &inneredgesum);
	_volumes[index]->_facetype.resize(facesum);
	break;
  }
  
  int counter = 0;

  while( counter < _volumes[index]->_facetype.size() &&
		 fin.getline( buffer, NumberOfCharactersLine) ){
	string line(buffer);

	if( string::npos != line.rfind(string("\r")) ){
	  line.erase( line.rfind(string("\r")) );
	}

	if( !Reader::CheckLine(&line) ) continue;

	int facetype = Reader::CountData(line, " ");

	_volumes[index]->_facetype[counter] = facetype;
	switch( facetype ){
	case reader::pcm::Volume::TRIANGLE:
	  {
		int order[3];
		sscanf(line.c_str(),
			   "%d %d %d",
			   &order[0],
			   &order[1],
			   &order[2]);
		for( int i = 0; i < 3; i++ ){
		  _volumes[index]->_conne.push_back(order[i]);
		}
	  }
	  break;
	case reader::pcm::Volume::RECTANGLE:
	  {
		int order[4];
		sscanf(line.c_str(),
			   "%d %d %d %d",
			   &order[0],
			   &order[1],
			   &order[2],
			   &order[3]);
		for( int i = 0; i < 4; i++ ){
		  _volumes[index]->_conne.push_back(order[i]);
		}

	  }
	  break;
	}
	counter++;
  }
  return 0;
}

library::graphics::Model* library::graphics::ReadPcm::createModel(void)
{
  char name[256];
  library::graphics::Model* model = new Model;
  for( size_t i = 0; i < _volumes.size(); i++ ){
	reader::pcm::Volume* volume = _volumes[i];

	volume->createNodeLocalIndex();

	library::graphics::PolygonBody* body 
	  = new library::graphics::PolygonBody(volume->_node_localindex.size());
	for( size_t j = 0; j < volume->_node_localindex.size(); j++ ){
	  body->set_vertex(j,_coord[volume->_node_localindex[j]]._coord);
	  cout << j << ":";
	  cout << volume->_node_localindex[j] << " => ";
	  cout << _coord[volume->_node_localindex[j]]._global_id << " ";
	  cout << _coord[volume->_node_localindex[j]]._coord.x << ",";
	  cout << _coord[volume->_node_localindex[j]]._coord.y << ",";
	  cout << _coord[volume->_node_localindex[j]]._coord.z << endl;
	  body->set_vertex_id(j,
						  _coord[volume->_node_localindex[j]]._global_id);
	}
	sprintf(name, "Volume%d", i);
	body->set_name(name);
	
	library::graphics::Cluster* tcluster = volume->createCluster(body, 3);
	library::graphics::Cluster* rcluster = volume->createCluster(body, 4);
	if( tcluster != NULL ){
	  library::graphics::Group* group = new Group(Group::TEXTURE,
												  Group::CLUSTER);
	  group->set_name("Triangle");
	  int index = body->appendCluster(tcluster);
	  group->addTarget(index);
	  body->appendGroup(group);
	}
	if( rcluster != NULL ){
	  library::graphics::Group* group = new Group(Group::TEXTURE,
												  Group::CLUSTER);
	  group->set_name("Rectangle");
	  int index = body->appendCluster(rcluster);
	  group->addTarget(index);
	  body->appendGroup(group);
	}
	body->appendGroup(new Group(Group::SELECTION, 
								Group::POLYGON));
	body->appendGroup(new Group(Group::SELECTION, 
								Group::VERTEX));
	model->appendPolygonBody(body, false);
  }
  model->createCenter();
  return model;
}

//=============================================================================
//	reader::pcm::Volume's method
//=============================================================================
reader::pcm::Volume::~Volume()
{
  _facetype.clear();
  _conne.clear();
  _node_localindex.clear();
}

int 
reader::pcm::Volume::createNodeLocalIndex(void)
{
  if( _facetype.size() == 0 ) return -1;
  if( _conne.size() == 0 ) return -1;

  int counter = 0;
  for( size_t i = 0; i < _facetype.size(); i++ ){

	for( int j = 0; j < _facetype[i]; j++ ){
	  bool overwrite = false;
	  // Checking overlap
	  for( size_t k = 0; k <  _node_localindex.size(); k++ ){
		if( _node_localindex[k] == _conne[counter + j] ){
		  _conne[counter + j] = k;
		  overwrite = true;
		  break;
		}
	  }
	  if( !overwrite ){
		_node_localindex.push_back(_conne[counter + j]);
		_conne[counter + j] = _node_localindex.size() -1;
	  }
	}
	counter += _facetype[i];
  }
}

/**
 * Argument type must be reader::pcm::Volume::FaceType
 * @author r-suzuki
 * @date 2009-1-20
 * @version 1.0
 */
library::graphics::Cluster* 
reader::pcm::Volume::createCluster(library::graphics::PolygonBody* body,
								   int type)
{
  int facesum=0;
  for( size_t i = 0; i < _facetype.size(); i++ ){
	if( _facetype[i] == type ){
	  facesum++;
	}
  }
  	  
  if( facesum == 0 ) return NULL;
  library::graphics::Cluster* cluster = NULL;
  switch( type ){
  case TRIANGLE:
	{
	  cluster = new library::graphics::TriangleCluster(facesum);
	  int counter = 0;
	  int polycounter = 0;
	  for( size_t i = 0; i < _facetype.size(); i++ ){
		if( _facetype[i] == type ){
		  int order[3];
		  order[0] = _conne[counter + 2];
		  order[1] = _conne[counter + 1];
		  order[2] = _conne[counter + 0];
		  cluster->setPolygon(body, polycounter++, i, order);
		}
		counter += _facetype[i];
	  }
	}
	break;
  case RECTANGLE:
	{
	  cluster = new library::graphics::RectangleCluster(facesum);
	  int counter = 0;
	  int polycounter = 0;
	  for( size_t i = 0; i < _facetype.size(); i++ ){
		if( _facetype[i] == type ){
		  int order[4];
		  order[0] = _conne[counter + 3];
		  order[1] = _conne[counter + 2];
		  order[2] = _conne[counter + 1];
		  order[3] = _conne[counter + 0];
		  cluster->setPolygon(body, polycounter++, i, order);
		}
		counter += _facetype[i];
	  }
	}
	break;
  default:
	cluster = NULL;
  }

  return cluster;
}

